// Copyright 2010, Vanya Davidenko.
// Используемая кодировка: UTF-8.

#ifndef SCRW_TESTING_HTML_TEXT_EXTRACTOR_TESTING_H_
#define SCRW_TESTING_HTML_TEXT_EXTRACTOR_TESTING_H_

#include <string>
#include <vector>

#include <gtest/gtest.h>
#include <libv/cast.h>
#include <unicode/unistr.h>

#include "html_text_extractor.h"
#include "curl.h"


namespace scrw
{

namespace testing
{

class HtmlTextExtractorTest : public ::testing::Test
{
  public:
    HtmlTextExtractorTest() : e(NULL) {}
    ~HtmlTextExtractorTest() { delete e; }

    virtual void SetUp()
    {
        HtmlTextExtractor::TagReplaceMap tag_replace_map;
        tag_replace_map["base"] = "__";

        e = new HtmlTextExtractor(tag_replace_map);
    }

    virtual void TearDown()
    {
        delete e;
        e = NULL;
    }


    Html Input(const ::std::string& str) const
    {
        return icu::UnicodeString(str.c_str(), I32(str.length()), US_INV);
    }


    ::std::string Ascii(const icu::UnicodeString& str) const
    {
        ::std::vector<char> tmp(str.length() + 1);
        // В str будут только латинские символы, так что кодировка — любая.
        str.extract(0, str.length(), &tmp[0], "windows-1251");

        return ::std::string(&tmp[0], tmp.size());
    }


    HtmlTextExtractor* e;
};


TEST_F(HtmlTextExtractorTest, CommentSimple)
{
    const char* str = "<!-- Comment -->OK";

    // Выглядит несколько уродливо, но удобно копировать и меньше дублирования
    // и в случае ошибки строки выводится на экран.
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentEOF)
{
    const char* str = "OK<!-- Comment";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentAtEnd)
{
    const char* str = "OK<!-- Comment -->";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentMinimal)
{
    const char* str = "<!---->OK";

    // Выглядит несколько уродливо, но удобно копировать и меньше дублирования
    // и в случае ошибки строки выводится на экран.
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentSpacesAfterEnd)
{
    const char* str = "<!-- My pretty comment--     >OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentBadMinimal)
{
    const char* str = "<!--->OK";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, Comments)
{
    // Один комментарий с пробелами, другой без.
    const char* str = "<!-- Comment -->OK<!--Comment-->";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentAfterComment)
{
    // Один комментарий с пробелами, другой без.
    const char* str = "<!-- Comment --><!--Comment-->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentsBetweenData)
{
    const char* str = "<!-- Comment -->O<!--Comment-->K";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithCdataBegin)
{
    const char* str = "<!-- Comment <![CDATA[ -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithCdataEnd)
{
    const char* str = "<!-- Comment ]]> -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithTagEnd)
{
    const char* str = "<!-- Comment> -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithQuote)
{
    const char* str = "<!-- Comment' -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithDoubleQuotes)
{
    const char* str = "<!-- Comment\" -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithBeginTag)
{
    const char* str = "<!-- Comment <b> -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithEndTag)
{
    const char* str = "<!-- Comment </b> -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CommentWithReplaceTag)
{
    const char* str = "<!-- Comment <a> -->OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, Doctype)
{
    const char* str = "<!DOCTYPE ... >OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, ServiceTag)
{
    const char* str = "<!? design.theme_dossier_if; ?>OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, ServiceTagAtBeginning)
{
    const char* str = "<!? design.theme_dossier_if; ?>OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, ServiceTagAtEnding)
{
    const char* str = "OK<!? design.theme_dossier_if; ?>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, XmlHeaderAtBeginning)
{
    const char* str = "<?xml version=\"1.0\" encoding=\"utf-8\"?>OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataSimple)
{
    const char* str = "<![CDATA[OK]]>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataMinimal)
{
    const char* str = "<![CDATA[]]>OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataEOF)
{
    const char* str = "OK<![CDATA[]]";
    EXPECT_STREQ("OK]]", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataAtBegin)
{
    const char* str = "<![CDATA[O]]>K";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataAEnd)
{
    const char* str = "O<![CDATA[K]]>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataAfterCdata)
{
    const char* str = "<![CDATA[O]]><![CDATA[K]]>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithCommentEnd)
{
    const char* str = "<![CDATA[O-->]]>K";
    EXPECT_STREQ("O-->K", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithTagEnd)
{
    const char* str = "<![CDATA[O>]]>K";
    EXPECT_STREQ("O>K", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithQuote)
{
    const char* str = "<![CDATA[O']]>K";
    EXPECT_STREQ("O'K", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithDoubleQuotes)
{
    const char* str = "<![CDATA[O\"]]>K";
    EXPECT_STREQ("O\"K",Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithBeginTag)
{
    const char* str = "<![CDATA[O<a>]]>K";
    EXPECT_STREQ("O<a>K", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithEndTag)
{
    const char* str = "<![CDATA[O</a>]]>K";
    EXPECT_STREQ("O</a>K", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithOmittingBeginTag)
{
    const char* str = "<![CDATA[O<script>]]>K";
    EXPECT_STREQ("O<script>K", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithReplaceTag)
{
    const char* str = "<![CDATA[O<a>]]>K";
    EXPECT_STREQ("O<a>K", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, CdataWithComment)
{
    const char* str = "<![CDATA[O<!-- comment -->]]>K";
    EXPECT_STREQ("O<!-- comment -->K", Ascii(e->Extract(Input(str))).c_str());
}




TEST_F(HtmlTextExtractorTest, TagSimple)
{
    const char* str = "<b>OK</b>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagSingle)
{
    const char* str = "<img src='123'/>OK";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithSpaces)
{
    const char* str = "<b   >OK</b  >";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagAfterTag)
{
    const char* str = "<img src='123'><b>OK</b>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagEOF)
{
    const char* str = "OK<img src='123";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagInText)
{
    const char* str = "O<b>K</b>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithAttributesInQuotes)
{
    const char* str = "O<a href='1'>K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithTwoAttributesInQuotes)
{
    const char* str = "O<a href='1' name='2'>K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithAttributesInDoubleQuotes)
{
    const char* str = "O<a href=\"1\">K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithAttributesWithoutQuotes)
{
    const char* str = "O<a href=1>K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithAttributesWithQuoteInDoubleQuotes)
{
    const char* str = "O<a href=\"'1\">K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithAttributesWithDoubleQuotesInQuote)
{
    const char* str = "O<a href='\"1'>K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithTwoAttributesWithMixedQuotes)
{
    const char* str = "O<a href='1' name=\"2\">K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagWithRightAngleBracketInAttribute)
{
    const char* str = "O<a href='>'>K</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagBadNameWithSpace)
{
    // Так иногда пишут на форумах, что бы обмануть парсер.
    const char* str = "< b>OK< /b>";
    EXPECT_STREQ("< b>OK< /b>", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagBadUnclosedQuotes)
{
    const char* str = "OK<a href='1>Fail</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagBadUnclosedDoubleQuotes)
{
    const char* str = "OK<a href=\"1>Fail</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagBadMixedQuotes)
{
    const char* str = "OK<a href=\"1'>Fail</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagReplace)
{
    const char* str = "<base>OK</base>";
    EXPECT_STREQ("__OK__", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagReplaceCaseInsensetive)
{
    const char* str = "<bAse>OK</BASe>";
    EXPECT_STREQ("__OK__", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, EmptyTagReplace)
{
    const char* str = "<a>OK</a>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagReplaceWithAttributes)
{
    const char* str = "<base href='1'>OK</base>";
    EXPECT_STREQ("__OK__", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, TagDontReplaceWrongTag)
{
    const char* str = "<baseb href='1'>OK</baseb>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}



TEST_F(HtmlTextExtractorTest, OmittingTagSimple)
{
    const char* str = "OK<script>Fail</script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagScriptInScript)
{
    const char* str = "OK<script>Fail<script>Fail</scr\"+\"ipt>Fail</script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagCaseInsensitive)
{
    const char* str = "OK<sCripT>Fail</ScRiPt>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagEOF)
{
    const char* str = "OK<script>Fail</s";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}



TEST_F(HtmlTextExtractorTest, OmittingTagWithAttributes)
{
    const char* str = "OK<script language='javascript'>Fail</script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagWithAnotherBeginTag)
{
    const char* str = "OK<script language='javascript'><b>Fail</script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagWithAnotherEndTag)
{
    const char* str = "OK<script language='javascript'>Fail</b></script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagWithAnotherOmittingTagInside)
{
    const char* str = "OK<script><style>Fail</style></script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagWithCommentWithEndTag)
{
    const char* str = "OK<script><!--</script>-->Fail</script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, OmittingTagWithCdataWithEndTag)
{
    const char* str = "OK<script>1<![CDATA[</script>]]>Fail</script>";
    EXPECT_STREQ("OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadLeftAngleBracketsInText)
{
    const char* str = "<<OK";
    EXPECT_STREQ("<", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, LeftAngleBracketsInText)
{
    const char* str = "<< OK";
    EXPECT_STREQ("<< OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, LeftAndRightAngleBracketsInText)
{
    const char* str = "<> OK";
    EXPECT_STREQ("<> OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, RightAngleBracketsInText)
{
    const char* str = ">>OK";
    EXPECT_STREQ(">>OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, UnicodeEntity)
{
    const char* str = "&#38;";
    EXPECT_STREQ("&", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, UnicodeHexEntity)
{
    const char* str = "&#x26;";
    EXPECT_STREQ("&", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, UnicodeEntityAtBegin)
{
    const char* str = "&#38;OK";
    EXPECT_STREQ("&OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, UnicodeEntityAtEnd)
{
    const char* str = "OK&#38;";
    EXPECT_STREQ("OK&", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadUnicodeEntityWithLetter)
{
    const char* str = "&#3x8;";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadTooBigUnicodeEntity)
{
    const char* str = "&#11111111;";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadEmptyUnicodeEntity)
{
    const char* str = "&#;";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadEmptyUnclosedUnicodeEntity)
{
    const char* str = "&#";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadEmptyHexUnicodeEntity)
{
    const char* str = "&#x;";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadEmptyHexUnclosedUnicodeEntity)
{
    const char* str = "&#x";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}



TEST_F(HtmlTextExtractorTest, HtmlEntity)
{
    const char* str = "&amp;";
    EXPECT_STREQ("&", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, HtmlEntityAtBegin)
{
    const char* str = "&amp;OK";
    EXPECT_STREQ("&OK", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, HtmlEntityAtEnd)
{
    const char* str = "OK&amp;";
    EXPECT_STREQ("OK&", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadEmptyHtmlEntity)
{
    const char* str = "&;";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadMissingHtmlEntity)
{
    const char* str = "&xxx;";
    EXPECT_STREQ("", Ascii(e->Extract(Input(str))).c_str());
}


TEST_F(HtmlTextExtractorTest, BadUnclosedHtmlEntity)
{
    // Повторяем нестандартное поведение браузеров.
    const char* str = "&amp OK";
    EXPECT_STREQ("& OK", Ascii(e->Extract(Input(str))).c_str());
}


}  // testing

}  // scrw

#endif  // SCRW_TESTING_HTML_TEXT_EXTRACTOR_TESTING_H_
